package ru.spb.osll.myfit.client.widget;

import com.google.gwt.cell.client.*;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.NativeEvent;
import com.google.gwt.i18n.client.DateTimeFormat;
import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
import com.google.gwt.user.cellview.client.CellTable;
import com.google.gwt.user.cellview.client.Column;
import com.google.gwt.user.cellview.client.ColumnSortEvent;
import com.google.gwt.user.cellview.client.SimplePager;
import com.google.gwt.user.cellview.client.SimplePager.TextLocation;
import com.google.gwt.user.client.ui.HasHorizontalAlignment;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.view.client.ListDataProvider;
import ru.spb.osll.myfit.common.ExecutingResult;
import ru.spb.osll.myfit.common.ExecutingResultComparatorFactory;
import ru.spb.osll.myfit.common.ExecutingResultComparatorFactory.ComparatorType;
import ru.spb.osll.myfit.common.PageExecutingResult;

import java.util.Date;
import java.util.LinkedList;
import java.util.List;

public class ResultTableWidget extends CellTable<ExecutingResult> implements ResultTable {

    private ListDataProvider<ExecutingResult> dataProvider;
    private List<ExecutingResult> results;
    private List<ResultTableEventListener> m_listeners;
    private VerticalPanel m_mainPanel;
    private SimplePager m_pager;

    private static final int PAGE_SIZE = 15;
    
    public ResultTableWidget() {
        m_listeners = new LinkedList<ResultTableEventListener>();
        initializeTable();
        initializeWidget();
    }

    private void initializeWidget() {
      SimplePager.Resources pagerResources = GWT.create(SimplePager.Resources.class);
      m_pager = new SimplePager(TextLocation.CENTER, pagerResources, false, 0, true);
      m_pager.setDisplay(this);
      m_pager.setVisible(true);
      m_pager.setPageSize(PAGE_SIZE);
      
      m_mainPanel = new VerticalPanel();
      m_mainPanel.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_CENTER);
      m_mainPanel.add(this);
      m_mainPanel.add(m_pager);
    }

    private void initializeTable() {
        setWidth("100%", true);

        dataProvider = new ListDataProvider<ExecutingResult>();
        dataProvider.addDataDisplay(this);
        results = dataProvider.getList();

        initTableColumns();
    }

    private void initTableColumns() {

        ColumnSortEvent.ListHandler<ExecutingResult> columnSortHandler = new ColumnSortEvent.ListHandler<ExecutingResult>(results);
        addColumnSortHandler(columnSortHandler);

        Column<ExecutingResult, ExecutingResult> pageNameColumn = new Column<ExecutingResult, ExecutingResult>(new PageNameCell()) {

            @Override
            public ExecutingResult getValue(ExecutingResult object) {
                return object;
            }

        };
        pageNameColumn.setSortable(true);
        addColumn(pageNameColumn, "Page");

        columnSortHandler.setComparator(pageNameColumn, ExecutingResultComparatorFactory.createComparator(ComparatorType.BY_NAME));

        Column<ExecutingResult, Date> timeColumn = new Column<ExecutingResult, Date>(new DateCell(DateTimeFormat.getFormat("dd.MM.yy h:mm a"))) {

            @Override
            public Date getValue(ExecutingResult object) {
                return object.getStartTime();
            }

        };
        timeColumn.setSortable(true);
        addColumn(timeColumn, "Start Time");

        columnSortHandler.setComparator(timeColumn, ExecutingResultComparatorFactory.createComparator(ComparatorType.BY_TIME));

        Column<ExecutingResult, String> progressColumn = new Column<ExecutingResult, String>(new TextCell()) {

            @Override
            public String getValue(ExecutingResult object) {
                return object.getState().toString();
            }

        };
        progressColumn.setSortable(true);
        addColumn(progressColumn, "Progress");

        columnSortHandler.setComparator(progressColumn, ExecutingResultComparatorFactory.createComparator(ComparatorType.BY_STATE));

        Column<ExecutingResult, String> summaryColumn = new Column<ExecutingResult, String>(new TextCell()) {

            @Override
            public String getValue(ExecutingResult object) {
              return object.getStatusString();
            }

        };
        addColumn(summaryColumn, "Summary");

        ActionCell<ExecutingResult> stopCell = new ActionCell<ExecutingResult>("Stop", new ActionCell.Delegate<ExecutingResult>() {

            @Override
            public void execute(ExecutingResult object) {
                notifyListeners(new ResultTableEvent(ResultTableEvent.ResultTableEventType.STOP_EXECUTION, object));
            }
        });

//        Column<ExecutingResult, ExecutingResult> stopColumn = new Column<ExecutingResult, ExecutingResult>(new StopButtonCell("Stop", "")) {
//
//            @Override
//            public ExecutingResult getValue(ExecutingResult object) {
//                return object;
//            }
//
//        };
//        addColumn(stopColumn, "Stop");
//        setColumnWidth(stopColumn, 100, com.google.gwt.dom.client.Style.Unit.PX);

        getColumnSortList().push(pageNameColumn);

    }

    public void addResult(final ExecutingResult result) {
        if (findListElementByID(results, result.getId()) != -1)
            return;
        results.add(result);
    }

    public void removeResult(String id) {
        int index = findListElementByID(results, id);
        if (index != -1)
            results.remove(index);
        dataProvider.flush();
    }

    public void updateResult(final ExecutingResult result) {
        int index = findListElementByID(results, result.getId());
        if (index == -1)
            return;
        results.set(index, result);
        dataProvider.flush();
    }


    public void addResultTableEventListener(ResultTableEventListener listener) {
        m_listeners.add(listener);
    }

    public void removeResultTableEventListener(ResultTableEventListener listener) {
        m_listeners.remove(listener);
    }

    private void notifyListeners(ResultTableEvent event) {
        for (ResultTableEventListener l : m_listeners)
            l.actionPerformed(event);
    }

    private class PageNameCell extends AbstractCell<ExecutingResult> {

        public PageNameCell() {
            super("click");
        }

        @Override
        public void render(com.google.gwt.cell.client.Cell.Context context,
                           ExecutingResult value, SafeHtmlBuilder sb) {
            sb.appendHtmlConstant("<div class='testResultTablePageName'>" + value.getName() + "</div>");
        }

        public void onBrowserEvent(Context context, Element parent, PageExecutingResult value,
                                   NativeEvent event, ValueUpdater<ExecutingResult> valueUpdater) {
            if (value == null) {
                return;
            }

            super.onBrowserEvent(context, parent, value, event, valueUpdater);

            if ("click".equals(event.getType())) {
                notifyListeners(new ResultTableEvent(ResultTableEvent.ResultTableEventType.OPEN_PAGE_RESULT, value));
            }
        }

    }

    private class StopButtonCell extends AbstractCell<PageExecutingResult> {

        private final String style;
        private final String text;

        public StopButtonCell(String text, String style) {
            super("click");
            this.style = style;
            this.text = text;
        }

        @Override
        public void render(com.google.gwt.cell.client.Cell.Context context,
                           PageExecutingResult value, SafeHtmlBuilder sb) {
            StringBuilder html = new StringBuilder();
            html.append("<button class='").append(style).append('\'');
            if (value.getState().equals(ExecutingResult.ExecutingState.FINISH)
                    || value.getState().equals(ExecutingResult.ExecutingState.FAIL))
                html.append("disabled='disabled'");
            html.append('>').append(text).append("</button>");
            sb.appendHtmlConstant(html.toString());
        }

        public void onBrowserEvent(Context context, Element parent, PageExecutingResult value,
                                   NativeEvent event, ValueUpdater<PageExecutingResult> valueUpdater) {
            if (value == null) {
                return;
            }

            super.onBrowserEvent(context, parent, value, event, valueUpdater);

            if ("click".equals(event.getType())) {
                notifyListeners(new ResultTableEvent(ResultTableEvent.ResultTableEventType.STOP_EXECUTION, value));
            }
        }

    }

    private int findListElementByID(List<ExecutingResult> l, String id) {
        ExecutingResult r;
        for (int i = 0; i < l.size(); i++) {
            r = l.get(i);
            if (r.getId().equals(id))
                return i;
        }
        return -1;
    }

    @Override
    public Widget getWidget() {   
      return m_mainPanel;
    }
}